package com.shiro.demo.framework.aspectj;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.shiro.demo.common.ServletUtils;
import com.shiro.demo.common.ShiroUtils;
import com.shiro.demo.project.monitor.operlog.domain.OperLog;
import com.shiro.demo.project.monitor.operlog.services.IOperLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Map;

@Aspect
@Component
public class LogAspect {

    @Autowired
    IOperLogService operLogService;

    @Pointcut("@annotation(com.shiro.demo.framework.aspectj.Log)")
    public void method(){}

    @AfterReturning(pointcut = "method()")
    public void afterReturning(JoinPoint point){
        handleLog(point, null);
    }

    @AfterThrowing(pointcut = "method()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Throwable e){
        handleLog(joinPoint, e);
    }
    /**
     * 获取@Log批注
     * @param joinPoint
     * @return
     */
    protected Log getLogAnnotation(JoinPoint joinPoint){
        MethodSignature methodSig = (MethodSignature)joinPoint.getSignature();
        return methodSig.getMethod().getAnnotation(Log.class);
    }

    protected String getMethodName(JoinPoint joinPoint){
        return ((MethodSignature)joinPoint.getSignature()).getName();
    }

    protected void handleLog(JoinPoint joinPoint, Throwable e){
        try {
            OperLog operLog = new OperLog();
            Log log = getLogAnnotation(joinPoint);
            operLog.setModule(log.module());
            operLog.setOperator(log.operator());
            operLog.setAction(log.action());

            operLog.setUrl(ServletUtils.getRequestUrl());
            operLog.setHost_ip(ShiroUtils.getHost());
            operLog.setUsername(ShiroUtils.getUsername());

            if (e == null) {
                operLog.setStatus(true);
            } else {
                operLog.setStatus(false);
                String s = e.getMessage();
                if(StringUtils.hasText(s)) {
                    operLog.setError_msg(s.substring(0, Math.min(s.length(), 1024)));
                }
            }

            if(log.isSaveRequestData()) {
                Map<String, String[]> map = ServletUtils.getRequest().getParameterMap();
                String s = new ObjectMapper().writeValueAsString(map);
                if(s != null) {
                    operLog.setParams(s.substring(0, Math.min(1024, s.length())));
                }
            }
            operLog.setOperate_time(LocalDateTime.now());
            operLogService.save(operLog);
        }catch (Throwable t){
            System.out.println("Exception ocurred in LogAspect "  + t.getMessage());
            t.printStackTrace();
        }
    }
}
